<?php
/**
 * Created by PhpStorm.
 * User: lhl
 * Date: 2020/12/8
 * Time: 16:34
 * Features: 数据库列表
 */

namespace app\adminapiv3\model;


use app\common\exception\CustomException;
use app\common\model\depots\DepotsBaseModel;
use app\common\service\Encrypt;
use think\Exception;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Env;

class ServerDatabasesModel extends BaseModel
{
    //目前参与了分表分库的数据库标识 => 类型 对应数据表中source字段
    const DEPOTS_DATABASE_KEY = [
        'learn_data_database' => 2, //学习数据
        'access_log_database' => 3, //访问日志
    ];

    /**
     * 搜索器
     * @field source 数据库类型
     */
    public function searchSourceAttr($query, $value, $data){
        $value = trim($value);
        if(strlen($value)){
            $query->where('source','eq',$value);
        }
    }

    /**
     * 搜索器
     * @field database 数据库名称
     */
    public function searchDatabaseAttr($query, $value, $data){
        $value = trim($value);
        if(strlen($value)){
            $query->where('database','like',"%{$value}%");
        }
    }

    /**
     * 搜索器
     * @field hostname IP地址
     */
    public function searchHostnameAttr($query, $value, $data){
        $value = trim($value);
        if(strlen($value)){
            $query->where('hostname','like',"%{$value}%");
        }
    }

    /**
     * 搜索器
     * @field hostport 端口
     */
    public function searchHostportAttr($query, $value, $data){
        $value = trim($value);
        if(strlen($value)){
            $query->where('hostport','like',"%{$value}%");
        }
    }

    /**
     * 查询后台列表
     * @param array $search 搜索参数
    */
    public function getList(array $search){
        return $this->withSearch(['source','database','hostname','hostport'],$search)
            ->field('username,password,username_salt,password_salt',true)
            ->paginate()->toArray();
    }

    /**
     * 根据当前数据库配置文件,将数据刷新入mysql作展示用
    */
    public function refreshMysqlData(){
        set_time_limit(0);
        //读取是否需要刷新,默认为需要
        $lock = Cache::get(DepotsBaseModel::IS_NEED_ADMIN_REFRESH_DATABASE_LIST_KEY,1);
        if(!$lock)  return true;

        //读取根据配置文件生成的数据
        $config = $this->getChildDatabaseConfigFile();
        //表前缀
        $prefix = Config::get('database.prefix','');
        //入库
        $this->startTrans();
        try{
            //统一先删除后添加
            $sql = "truncate table {$prefix}server_databases";
            $this->execute($sql);

            if (!$this->field(true)->insertAll($config)) {
                $this->rollback();
                throw new CustomException('刷新数据失败',433);
            }
            $this->commit();
            //将锁重置为不需要刷新
            Cache::set(DepotsBaseModel::IS_NEED_ADMIN_REFRESH_DATABASE_LIST_KEY,0);
            return true;
        }catch (Exception $e){
            $this->rollback();
            throw new CustomException('刷新数据失败：'.$e->getMessage(),433);
        }

    }


    /**
     * 根据当前数据库配置文件,获取对应的mysql格式的数据
     * @param bool $isEncrypt 是否将账号密码作加密处理
     */
    public function getChildDatabaseConfigFile($isEncrypt = true){
        //主库配置的加密盐
        $firstConfigSalt = [
            'username_salt' => Encrypt::salt(),
            'password_salt' => Encrypt::salt(),
        ];
        //读取主库配置
        $firstConfig = [
            'master' => [
                'type' => Config::get('database.type'),
                'hostname' => Config::get('database.hostname'),
                'database' => Config::get('database.database'),
                'username' => $isEncrypt ? Encrypt::encrypt(Config::get('database.username'),$firstConfigSalt['username_salt']) : Config::get('database.username') ,
                'password' => $isEncrypt ? Encrypt::encrypt(Config::get('database.password'),$firstConfigSalt['password_salt']) : Config::get('database.password') ,
                'hostport' => Config::get('database.hostport'),
                'prefix' => Config::get('database.prefix'),
                'source' => 1,
                'username_salt' => $firstConfigSalt['username_salt'],
                'password_salt' => $firstConfigSalt['password_salt']
            ]
        ];

        //读取子库配置
        $path = Env::get('config_path'). '/'.DepotsBaseModel::CHILD_DATABASE_CONFIG_FILE;
        if (is_file($path)) {
            //热加载配置文件
            $configFile = require $path;
            //结果
            $config = [];
            foreach ($configFile as $k => $item){
                //加密盐
                $itemSalt = [
                    'username_salt' => Encrypt::salt(),
                    'password_salt' => Encrypt::salt(),
                ];

                //对字段进行规范排序,避免因为配置文件字段乱序而造成批量写入时报错
                $itemConfig = [
                    'type' => $item['type'],
                    'hostname' => $item['hostname'],
                    'database' => $item['database'],
                    'username' => $isEncrypt ? Encrypt::encrypt($item['username'],$itemSalt['username_salt']) : $item['username'],    //账号、密码进行加密
                    'password' => $isEncrypt ? Encrypt::encrypt($item['password'],$itemSalt['password_salt']) : $item['password'],
                    'hostport' => $item['hostport'],
                    'prefix' => $item['prefix'],
                    'source' => 0, //确定数据库类型 当前默认为0 未知
                    'username_salt' => $itemSalt['username_salt'],
                    'password_salt' => $itemSalt['password_salt']
                ];


                //匹配数据库类型
                foreach (self::DEPOTS_DATABASE_KEY as $key => $source){
                    //拼接下划线后判断
                    if(strpos($k,$key . '_') !== false){
                        $itemConfig['source'] = $source;
                        break;
                    }
                }
                //合并结果
                $config[] = $itemConfig;
            }

        }else{
            $config = [];
        }

        $config = array_merge($firstConfig,$config);
        return $config;
    }

}